#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include <conio.h>
#include <unistd.h>
#include <windows.h>

#define WIDTH 30
#define HEIGHT 20
#define SPEED 0.1

#define BALL_X 0
#define BALL_Y 1


void init_map(char [][WIDTH]);
void printout(char [][WIDTH]);
bool ball_upd(char [][WIDTH], float [], float [], const int, const int);
void ball_board_check(int, int, float [], float);

void gotoxy(int x,int y)//类似于清屏函数，光标移动到原点位置进行重画
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(handle,pos);
}

// init the pos struct for the function
struct pos
{
    const int x;
    int y;
};

int main(void)
{
    CONSOLE_CURSOR_INFO cursor_info = {1, 0}; /*隐藏光标*/
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
    bool flag = true;
    char map[HEIGHT][WIDTH];
    //init the map
    init_map(map);

    //init board
    static struct pos B1 = {3, 9}, B2 = {WIDTH - 3, 9};

    //init ball
    float ball_pos[2] = {1, 1}; //x,y
    float ball_direc[2] = {SPEED, SPEED};// 前一个值代表水平速度的方向右正、左负，后一个代表水平方向速度下正，上负。


    //the main loop
    while (flag)
    {
        board(map, &B1, &B2);
        flag = ball_upd(map, ball_pos, ball_direc, B1.y, B2.y);
        printout(map);
    }
    //the main loop

    return 0;
}



void init_map(char map[][WIDTH])
{
    // init map
    for (int i = 0; i < HEIGHT; i++)
    {
        // init the first&last line
        if (i == 0 || i == HEIGHT - 1)
        {
            for (int j = 0; j < WIDTH; j++)
            {
                map[i][j] = '=';
            }
        }
        else
        {
            // init the wall on left&right
            map[i][0] = '#';
            map[i][WIDTH - 1] = '#';
            for (int j = 1; j < WIDTH - 1; j++)
            {
                map[i][j] = ' ';
            }
        }
    }
    //init map
}


void printout(char map[][WIDTH])
{
    //print out the map
    gotoxy(0,0);
    char *p;
    p = &map[0][0];

    int a = 0;
    while (p < &map[HEIGHT- 1][WIDTH - 1] + 1)
    {
        if (a == WIDTH)
        {
            printf("\n");
            a = 0;
        }
        printf("%c", *p++);
        a++;
    }
    //print out map
}


void board(char map[][WIDTH], struct pos* B1, struct pos* B2)
{
  
  init_map(map);

    char ctrl;
    int save1y, save2y; 
    save1y = (*B1).y;
    save2y = (*B2).y;
    if (kbhit())
    {
      ctrl = getch();
      if (ctrl == 'w' && (*B1).y != 2) /*p1：ws上下*/
        (*B1).y -= 1;                  /*p2：85上下*/
      if (ctrl == 's' && (*B1).y != 17)
        (*B1).y += 1;
      if (ctrl == '8' && (*B2).y != 2)
        (*B2).y -= 1;
      if (ctrl == '5' && (*B2).y != 17)
        (*B2).y += 1;
      ctrl = '0';
    }

    for (int i = -1; i != 2; i++)
      map[save1y + i][(*B1).x] = map[save2y + i][(*B2).x] = ' '; /*清空原来的板*/
    for (int i = -1; i != 2; i++)
      map[(*B1).y + i][(*B1).x] = map[(*B2).y + i][(*B2).x] = '|'; /*放上新的板*/
}


bool ball_upd(char map[][WIDTH], float ball_pos[], float ball_direc[], const int B1, const int B2)
{
    int y_next = ball_pos[BALL_Y] + ball_direc[BALL_Y], 
        x_next = ball_pos[BALL_X] + ball_direc[BALL_X];

    // game over?
    if (x_next == 0 || x_next == WIDTH - 1)
        return false;

    //may hit the left board
    else if (x_next == 3)
    {
        ball_board_check(y_next, B1, ball_direc, SPEED);
    }

    // may hit the right board
    else if (x_next == WIDTH - 3)
    {
        ball_board_check(y_next, B2, ball_direc, SPEED);
    }

    // may hit top and bottom
    else if (y_next == 0 || y_next == HEIGHT - 1)
    {
        ball_direc[BALL_Y] *= -1;
    }

    // update the ball
    int ballx, bally;
    ballx = (int) (ball_pos[BALL_X] += ball_direc[BALL_X]);
    bally = (int) (ball_pos[BALL_Y] += ball_direc[BALL_Y]);
    map[bally][ballx] = '@';
    return true;
}


void ball_board_check(int y_next, int B, float ball_direc[], float speed)
{
    if (y_next == B)
    {
            ball_direc[BALL_X] *= -1.2;
            ball_direc[BALL_Y] = 0;
    }
    else if (y_next == B + 1)
    {
            ball_direc[BALL_X] *= -1;
            ball_direc[BALL_Y] = speed;
    }
    else if (y_next == B - 1)
    {
            ball_direc[BALL_X] *= -1;
            ball_direc[BALL_Y] = -speed;
    }
}
